#pragma once


#include <iostream>
#include <sys/epoll.h>
#include <memory>
#include "Log.hpp"
#include "Comm.hpp"

const static int gsize = 128;

using namespace log_ns;


class Multiplex
{
private:
public:
    virtual bool AddEvent(int fd, uint32_t events) = 0;
    virtual int Wait(struct epoll_event revs[], int num, int timeout) = 0;
    virtual bool ModEvent(int fd, uint32_t events) = 0;
    virtual bool DelEvent(int fd) = 0;

private:
};


class Epoller : public Multiplex
{
private:
    bool EventHelpter(int fd, uint32_t events, int oper)
    {
        struct epoll_event ev;
        ev.data.fd = fd;
        ev.events = events;
        int n = ::epoll_ctl(_epfd, oper, fd, &ev);
        if (n < 0)
        {
            LOG(ERROR, "epoll_ctl %s %d(%s) error: %d -> %s\n", _EventString[oper].c_str(), fd, EventsToString(events).c_str(), errno, strerror(errno));
            return false;
        }
        LOG(INFO, "epoll_ctl %s %d(%s) success\n", _EventString[oper].c_str(), fd, EventsToString(events).c_str());
        return true;
    }

public:
    Epoller()
    {
        _epfd = ::epoll_create(gsize);
        if (_epfd < 0)
        {
            LOG(FATAL, "epoll_create Error: %d -> %s\n", errno, strerror(errno));
            exit(EPOLL_CREATE_ERROR);
        }
        LOG(INFO, "epoll create success, epfd: %d\n", _epfd);

        _EventString[EPOLL_CTL_ADD] = "ADD";
        _EventString[EPOLL_CTL_MOD] = "MOD";
        _EventString[EPOLL_CTL_DEL] = "DEL";
    }

    const std::string EventsToString(uint32_t events)
    {
        std::string sep = " | ";
        std::string eventstr;
        if (events & EPOLLIN)
            eventstr += (sep + "EPOLLIN");
        if (events & EPOLLOUT)
            eventstr += (sep + "EPOLLOUT");
        if (events & EPOLLET)
            eventstr += (sep + "EPOLLET");
        return eventstr.substr(sep.size());
    }

    virtual int Wait(struct epoll_event revs[], int num, int timeout) override
    {
        return ::epoll_wait(_epfd, revs, num, timeout);
    }
    
    virtual bool AddEvent(int fd, uint32_t events) override
    {
        return EventHelpter(fd, events, EPOLL_CTL_ADD);
    }

    virtual bool ModEvent(int fd, uint32_t events) override
    {
        return EventHelpter(fd, events, EPOLL_CTL_MOD);
    }

    virtual bool DelEvent(int fd) override
    {
        return ::epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
    }

    ~Epoller()
    {}

private:
    int _epfd;
    std::unordered_map<int, std::string> _EventString;
};




// class Poller : public Multiplex
// {
// private:
// public:
// private:
// };

// class Selector : public Multiplex
// {
// private:
// public:
// private:
// };

